package com.tiny.conf.core.listener;

import com.tiny.conf.core.core.TinyConfZkConf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class TinyConfListenerFactory {
    private static Logger logger = LoggerFactory.getLogger(TinyConfListenerFactory.class);

    /**
     * xxl conf listener repository
     */
    private static ConcurrentHashMap<String, List<TinyConfListener>> keyListenerRepository = new ConcurrentHashMap<>();


    private static List<TinyConfListener> noKeyConfListener = Collections.synchronizedList(new ArrayList<TinyConfListener>());

    /**
     * add listener with xxl conf change
     * 该Java函数addListener用于向系统添加一个监听器，以便在配置发生变化时执行相应的回调操作。以下是详细的步骤说明：
     * 参数说明：
     *      key：字符串类型的键，用于标识具体的配置项。如果为空，则表示监听所有配置项。
     *      xxlConfListener：实现了XxlConfListener接口的对象，用于接收配置变化的通知。
     * 返回值：
     *      如果成功添加监听器，则返回true。
     *      如果xxlConfListener为null，则返回false。
     * 函数逻辑：
     *      首先检查xxlConfListener是否为null，如果是，则直接返回false。
     *      接下来检查key是否为空或空白字符串：
     *          如果为空或空白字符串，表示监听所有配置项。此时将xxlConfListener添加到noKeyConfListener列表中，并返回true。
 *          如果key不为空：
     *          调用XxlConfClient.get(key)方法，获取或初始化指定key的配置信息。
     *          从keyListenerRepository中获取与key关联的监听器列表listeners：
     *              如果listeners不存在，则创建一个新的ArrayList对象，并将其放入keyListenerRepository中。
     *      将xxlConfListener添加到listeners列表中。
     *      最后返回true，表示监听器添加成功。
     * 通过这种方式，该函数可以灵活地为特定配置项或所有配置项添加监听器，以便在配置发生变化时及时作出响应
     *
     * @param key              empty will listener all key
     * @param tinyConfListener
     * @return
     */
    public static boolean addListener(String key, TinyConfListener tinyConfListener) {
        if (tinyConfListener == null) {
            return false;
        }
        if (key == null || key.trim().length() == 0) {
            // listene all key used
            noKeyConfListener.add(tinyConfListener);
            return true;
        } else {
            // watch this key
            TinyConfZkConf.get(key);

            // listene this key
            List<TinyConfListener> listeners = keyListenerRepository.get(key);
            if (listeners == null) {
                listeners = new ArrayList<>();
                keyListenerRepository.put(key, listeners);
            }
            listeners.add(tinyConfListener);
            return true;
        }
    }


    /**
     * invoke listener on xxl conf change
     * 当配置项发生更改时调用此方法来通知监听器
     *
     * @param key   发生更改的配置项的键
     * @param value 配置项的新值
     */
    public static void onChange(String key, String value) {
        // 检查键的合法性，如果键为空或仅包含空白字符，则不执行任何操作
        if (key == null || key.trim().length() == 0) {
            return;
        }

        // 获取针对特定键的监听器列表
        List<TinyConfListener> keyListeners = keyListenerRepository.get(key);

        // 如果存在针对该键的监听器，则逐个触发它们
        if (keyListeners != null && keyListeners.size() > 0) {
            for (TinyConfListener listener : keyListeners) {
                try {
                    listener.onChange(key, value);
                } catch (Exception e) {
                    // 捕获并记录触发监听器时可能出现的异常
                    logger.error(e.getMessage(), e);
                }
            }
        }

        // 触发无键监听器，以便对所有配置项的更改进行统一处理
        if (noKeyConfListener.size() > 0) {
            for (TinyConfListener confListener : noKeyConfListener) {
                try {
                    confListener.onChange(key, value);
                } catch (Exception e) {
                    // 捕获并记录无键监听器触发时可能出现的异常
                    logger.error(e.getMessage(), e);
                }
            }
        }
    }



}
